package org.oep;

import java.io.IOException;
import java.util.Vector;

import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;

public class BTHandler implements Runnable, DiscoveryListener {
	private LocalDevice me;
	private DiscoveryAgent agent;
	
	private JMingle parent;
	private MingleTracker mingleHandler;
	private Vector devicesToScan = new Vector();
	private boolean antennaBusy = false;
	
	private volatile Thread scanThread;

	public BTHandler(JMingle parent, MingleTracker mingleHandler) {
		scanThread = new Thread(this);
		this.parent = parent;
		this.mingleHandler = mingleHandler;

		
		try {
			me = LocalDevice.getLocalDevice();
			agent = LocalDevice.getLocalDevice().getDiscoveryAgent();
		} catch(BluetoothStateException e) {
			parent.tell(e.getMessage());
			parent.tell("Couldn't initialize Bluetooth");
		}
	}
	
	/*
	 * Inherited from Runnable
	 */
	//--------------------------------------------------------------//
	
	public void run() {
		String val;
		int mins;
		
		try {
			if((val = (String) parent.getOpt("persistent_scan_interval")) != null)
				mins = Integer.parseInt( val );
			else
				mins = 5;
		}
		catch(Exception e) { // Invalid option format
			mins = 5;
		}
		
		while(true) {
			if(Thread.currentThread() == scanThread) {
				this.doNewSearch();
				try {
					Thread.sleep(mins * 60 * 1000);
				} catch(Exception e) {
					
				}
			}

		}	
		
	}
	
	/*
	 * Inherited from DiscoveryListener
	 */
	//--------------------------------------------------------------//
	
	public void deviceDiscovered(RemoteDevice device, DeviceClass type) {
		if(!devicesToScan.contains(device))
			devicesToScan.addElement(device);				
	}

	public void inquiryCompleted(int exitCode) {
		switch(exitCode) {
		case DiscoveryListener.INQUIRY_ERROR:
			devicesToScan.removeAllElements();
			parent.tell("Error during discovery");
			antennaBusy = false;
			parent.processCode(JMingle.EVENT_OCCURED);
			parent.processCode(JMingle.BT_SEARCH_DONE);
			return;
		case DiscoveryListener.INQUIRY_TERMINATED:
			devicesToScan.removeAllElements();
			parent.tell("Discovery terminated");
			antennaBusy = false;
			parent.processCode(JMingle.EVENT_OCCURED);
			parent.processCode(JMingle.BT_SEARCH_DONE);
			return;
		}
		
		
		for(int i = 0; i < devicesToScan.size(); i++) {
			RemoteDevice device = (RemoteDevice) devicesToScan.elementAt(i);
			String address = device.getBluetoothAddress().toUpperCase();
			
			// First: Get the device name, use the default if we couldn't find it
			String name;
			try {
				if(mingleHandler.isDefaultName(address))
					name = device.getFriendlyName(true);
				else
					name = device.getFriendlyName(false);
			}
			catch(IOException e) {
				name = "";
			}
			
			// If we already have it and the old name is the default name, update to the new one
			mingleHandler.doMingle(address, name);
		}
		devicesToScan.removeAllElements();
		
		antennaBusy = false;
		parent.processCode(JMingle.EVENT_OCCURED);
		
		if(!this.persistentScanActive()) {
			parent.processCode(JMingle.BT_SEARCH_DONE);
		} 
		
		mingleHandler.cycleSeenDevices();
	}

	public void serviceSearchCompleted(int arg0, int arg1) {
		
	}

	public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {

	}

	
	/*
	 * Helper functions for Bluetooth scans
	 */
	//--------------------------------------------------------------//
	
	public void doNewSearch() {
		this.stopScan();
		devicesToScan.removeAllElements();

		try {
			antennaBusy = agent.startInquiry(DiscoveryAgent.GIAC, this);
		}
		catch(Exception e) {
			parent.tell(e.getMessage());
		}
		
		if(antennaBusy)
			parent.processCode(JMingle.EVENT_OCCURED);
		else {
			
		}
	}
	
	public void stopScan() {
		// If we stop a scan, let's wait a bit before we start a new one
		if(antennaBusy)
			antennaBusy = !agent.cancelInquiry(this);
		else
			agent.cancelInquiry(this);
			
		if(!antennaBusy)
			try { Thread.sleep(100); } catch(Exception e) { }
	}
	
	public void killPersistentScan() {
		if(scanThread != null && scanThread.isAlive()) {
			scanThread = new Thread(this);
			parent.processCode(JMingle.EVENT_OCCURED);
		}
	}
	
	public void startPersistentScan() {
		killPersistentScan();
		if(scanThread == null) scanThread = new Thread(this);
		scanThread.start();
		parent.processCode(JMingle.EVENT_OCCURED);
	}
	
	public boolean antennaIsBusy() {
		return antennaBusy;
	}
	
	public boolean persistentScanActive() {
		if(scanThread != null)
			return scanThread.isAlive();
		else
			return false;
	}
	
	public boolean isInitialized() {
		return agent != null && me != null;
	}
	
}
